Import cal3d

Class CalPhysique

	Field m_model:CalModel
	Field m_normalize:Bool
	Field m_axisFactorX:Float
	Field m_axisFactorY:Float
	Field m_axisFactorZ:Float
	
	Method New()
		m_model = Null
		m_normalize = False
		m_axisFactorX = 0
		m_axisFactorY = 0
		m_axisFactorZ = 0
	End
	
	Method New(model:CalModel)
		m_model = model
		m_normalize = True
		m_axisFactorX = 1
		m_axisFactorY = 1
		m_axisFactorZ = 1	
	End
	
	Method calculateTangentSpaces:Int(submesh:CalSubmesh, mapId:Int, tangentSpaceBuffer:Float[], stride:Int=4)
	
		If mapId < 0 Or mapId >= submesh.getCoreSubmesh().getVectorVectorTangentSpace().Length Then
			Return 0
		Endif
		
		If stride <= 0 Then
			stride = 4
		Endif
		
		If tangentSpaceBuffer.Length < submesh.getVertexCount() * stride Then
			Return 0
		Endif
		
		' get bone vector of the skeleton
		Local vectorBone:CalBone[] = m_model.getSkeleton().getVectorBone()
	
		' get vertex vector of the submesh
		Local vectorVertex:CalVertex[] = submesh.getCoreSubmesh().getVectorVertex()
	
		' get tangent space vector of the submesh
		Local vectorTangentSpace:CalTangentSpace[] = submesh.getCoreSubmesh().getVectorVectorTangentSpace()[mapId]
	
		' get the number of vertices
		Local vertexCount:Int = submesh.getVertexCount()
	
		' calculate tangent for all submesh vertices
		Local ti:Int = 0
		Local v:CalVector = New CalVector
		For Local vertexId:Int = 0 To vertexCount-1
			Local tangentSpace:CalTangentSpace = vectorTangentSpace[vertexId]
	
			' get the vertex
			Local vertex:CalVertex = vectorVertex[vertexId]
	
			' initialize tangent
			Local tx:Float, ty:Float, tz:Float
			tx = 0
			ty = 0
			tz = 0
	
			' blend together all vertex influences
			Local influenceCount:Int = vertex.vectorInfluence.Length
			For Local influenceId:Int = 0 To influenceCount-1
				' get the influence
				Local influence:CalInfluence = vertex.vectorInfluence[influenceId]
	
				' get the bone of the influence vertex
				Local bone:CalBone = vectorBone[influence.boneId]
	
				' transform normal with current state of the bone
				v.assign(tangentSpace.tangent)
				v.multMatrixLocal(bone.getTransformMatrix())
	
				tx += influence.weight * v.x
				ty += influence.weight * v.y
				tz += influence.weight * v.z
			Next
	
			' re-normalize tangent if necessary
			If m_normalize = True then
				tx /= m_axisFactorX
				ty /= m_axisFactorY
				tz /= m_axisFactorZ
	
				Local scale:Float = 1 / Sqrt(tx * tx + ty * ty + tz * tz)
	
				tangentSpaceBuffer[ti    ] = tx * scale
				tangentSpaceBuffer[ti + 1] = ty * scale
				tangentSpaceBuffer[ti + 2] = tz * scale
			else
				tangentSpaceBuffer[ti    ] = tx
				tangentSpaceBuffer[ti + 1] = ty
				tangentSpaceBuffer[ti + 2] = tz
			Endif
	
			tangentSpaceBuffer[ti + 3] = tangentSpace.crossFactor
	
			' next vertex position in buffer
			ti += stride
		Next
	
		Return vertexCount		
	
	End
	
	Method calculateNormals:Int(submesh:CalSubmesh, normalBuffer:Float[], stride:Int=3)
	
		If stride <= 0 Then
			stride = 3
		Endif
		
		If normalBuffer.Length < submesh.getVertexCount() * stride Then
			Return 0
		Endif
		
		' get bone vector of the skeleton
		Local vectorBone:CalBone[] = m_model.getSkeleton().getVectorBone()
	
		' get vertex vector of the submesh
		Local vectorVertex:CalVertex[] = submesh.getCoreSubmesh().getVectorVertex()
	
		' get the number of vertices
		Local vertexCount:Int = submesh.getVertexCount()
	
		' get the sub morph target vector from the core sub mesh
		Local vectorSubMorphTarget:CalCoreSubMorphTarget[] = submesh.getCoreSubmesh().getVectorCoreSubMorphTarget()
	
		' calculate the base weight
		Local baseWeight:Float = submesh.getBaseWeight()
	
		' get the number of morph targets
		Local morphTargetCount:Int = submesh.getMorphTargetWeightCount()
	
		' calculate normal for all submesh vertices
		Local ni:Int = 0
		Local normal:CalVector = New CalVector
		Local v:CalVector = New CalVector
		For Local vertexId:Int = 0 To vertexCount-1
			' get the vertex
			Local vertex:CalVertex = vectorVertex[vertexId]
	
			' blend the morph targets
			If baseWeight = 1 Then
				normal.x = vertex.normal.x
				normal.y = vertex.normal.y
				normal.z = vertex.normal.z
			Else
				normal.x = baseWeight * vertex.normal.x
				normal.y = baseWeight * vertex.normal.y
				normal.z = baseWeight * vertex.normal.z
	
				For Local morphTargetId:Int = 0 To morphTargetCount-1
					Local blendVertex:CalBlendVertex = vectorSubMorphTarget[morphTargetId].getVectorBlendVertex()[vertexId]
					Local currentWeight:Float = submesh.getMorphTargetWeight(morphTargetId)
					normal.x += currentWeight * blendVertex.normal.x
					normal.y += currentWeight * blendVertex.normal.y
					normal.z += currentWeight * blendVertex.normal.z
				Next
			Endif
	
			' initialize normal
			Local nx:Float, ny:Float, nz:Float
			nx = 0
			ny = 0
			nz = 0
	
			' blend together all vertex influences
			Local influenceCount:Int = vertex.vectorInfluence.Length
			If influenceCount = 0 Then
				nx = normal.x
				ny = normal.y
				nz = normal.z
			Else 
				For Local influenceId:Int = 0 To influenceCount-1
					' get the influence
					Local influence:CalInfluence = vertex.vectorInfluence[influenceId]
	
					' get the bone of the influence vertex
					Local bone:CalBone = vectorBone[influence.boneId]
	
					' transform normal with current state of the bone
					v.assign(normal)
					v.multMatrixLocal(bone.getTransformMatrix())
	
					nx += influence.weight * v.x
					ny += influence.weight * v.y
					nz += influence.weight * v.z
				Next
			Endif
	
			' re-normalize normal if necessary
			If m_normalize = True Then
				nx /= m_axisFactorX
				ny /= m_axisFactorY
				nz /= m_axisFactorZ
	
				Local scale:Float = 1 / Sqrt(nx * nx + ny * ny + nz * nz)
	
				normalBuffer[ni    ] = nx * scale
				normalBuffer[ni + 1] = ny * scale
				normalBuffer[ni + 2] = nz * scale
			Else
				normalBuffer[ni    ] = nx
				normalBuffer[ni + 1] = ny
				normalBuffer[ni + 2] = nz
			Endif
	
			ni += stride
		Next
	
		Return vertexCount		
	
	End
	
	Method calculateVertices:Int(submesh:CalSubmesh, vertexBuffer:Float[], stride:Int=3)
	
		If stride <= 0 Then
			stride = 3
		Endif
		
		If vertexBuffer.Length < submesh.getVertexCount() * stride Then
			Return 0
		Endif
		
		' get bone vector of the skeleton
		Local vectorBone:CalBone[] = m_model.getSkeleton().getVectorBone()
	
		' get vertex vector of the submesh
		Local vectorVertex:CalVertex[] = submesh.getCoreSubmesh().getVectorVertex()
	
		' get physical property vector of the core submesh
		Local vectorPhysicalProperty:CalPhysicalProperty[] = submesh.getCoreSubmesh().getVectorPhysicalProperty()
	
		' get the number of vertices
		Local vertexCount:Int = submesh.getVertexCount()
	
		' get the sub morph target vector from the core sub mesh
		Local vectorSubMorphTarget:CalCoreSubMorphTarget[] = submesh.getCoreSubmesh().getVectorCoreSubMorphTarget()
	
		' calculate the base weight
		Local baseWeight:Float = submesh.getBaseWeight()
	
		' get the number of morph targets
		Local morphTargetCount:Int = submesh.getMorphTargetWeightCount()
	
		' calculate all submesh vertices
		Local vi:Int = 0
		Local position:CalVector = New CalVector
		Local v:CalVector = New CalVector
		For Local vertexId:Int = 0 To vertexCount-1
			' get the vertex
			Local vertex:CalVertex = vectorVertex[vertexId]
	
			' blend the morph targets
			position.assign(0, 0, 0)
			If baseWeight = 1 Then
				position.x = vertex.position.x
				position.y = vertex.position.y
				position.z = vertex.position.z
			Else
				position.x = baseWeight * vertex.position.x
				position.y = baseWeight * vertex.position.y
				position.z = baseWeight * vertex.position.z
	
				For Local morphTargetId:Int = 0 To morphTargetCount-1
					Local blendVertex:CalBlendVertex = vectorSubMorphTarget[morphTargetId].getVectorBlendVertex()[vertexId]
					Local currentWeight:Float = submesh.getMorphTargetWeight(morphTargetId)
					position.x += currentWeight * blendVertex.position.x
					position.y += currentWeight * blendVertex.position.y
					position.z += currentWeight * blendVertex.position.z
				Next
			Endif
	
			' initialize vertex
			Local x:Float, y:Float, z:Float
			x = 0
			y = 0
			z = 0
	
			' blend together all vertex influences
			Local influenceCount:Int = vertex.vectorInfluence.Length
			If influenceCount = 0 Then
				x = position.x
				y = position.y
				z = position.z
			Else
				For Local influenceId:Int = 0 To influenceCount-1
					' get the influence
					Local influence:CalInfluence = vertex.vectorInfluence[influenceId]
	
					' get the bone of the influence vertex
					Local bone:CalBone = vectorBone[influence.boneId]
	
					' transform vertex with current state of the bone
					v.assign(position)
					v.multMatrixLocal(bone.getTransformMatrix())
					v.addLocal(bone.getTranslationBoneSpace())
	
					x += influence.weight * v.x
					y += influence.weight * v.y
					z += influence.weight * v.z
				Next
			Endif
	
			' save vertex position
			If submesh.getCoreSubmesh().getSpringCount() > 0 And submesh.hasInternalData() Then
				' get the pgysical property of the vertex
				Local physicalProperty:CalPhysicalProperty = vectorPhysicalProperty[vertexId]
	
				' assign new vertex position if there is no vertex weight
				If physicalProperty.weight = 0 then
					vertexBuffer[vi    ] = x * m_axisFactorX
					vertexBuffer[vi + 1] = y * m_axisFactorY
					vertexBuffer[vi + 2] = z * m_axisFactorZ
				Endif
			Else
				vertexBuffer[vi    ] = x * m_axisFactorX
				vertexBuffer[vi + 1] = y * m_axisFactorY
				vertexBuffer[vi + 2] = z * m_axisFactorZ
			Endif
	
			vi += stride
		Next
	
		Return vertexCount	
	
	End
	
	Method calculateVertex:CalVector(submesh:CalSubmesh, vertexId:Int)
	
	' get bone vector of the skeleton
	Local vectorBone:CalBone[] = m_model.getSkeleton().getVectorBone()

	' get vertex vector of the submesh
	Local vectorVertex:CalVertex[] = submesh.getCoreSubmesh().getVectorVertex()

	' get the sub morph target vector from the core sub mesh
	Local vectorSubMorphTarget:CalCoreSubMorphTarget[] = submesh.getCoreSubmesh().getVectorCoreSubMorphTarget()
	
	' calculate the base weight
	Local baseWeight:Float = submesh.getBaseWeight()

	' get the number of morph targets
	Local morphTargetCount:Int = submesh.getMorphTargetWeightCount()

	' get the vertex
	Local vertex:CalVertex = vectorVertex[vertexId]

	' blend the morph targets
	Local position:CalVector = New CalVector(0, 0, 0)
	If baseWeight = 1 then
		position.x = vertex.position.x
		position.y = vertex.position.y
		position.z = vertex.position.z
	Else
		position.x = baseWeight * vertex.position.x
		position.y = baseWeight * vertex.position.y
		position.z = baseWeight * vertex.position.z

		For Local morphTargetId:Int = 0 To morphTargetCount-1
			Local blendVertex:CalBlendVertex = vectorSubMorphTarget[morphTargetId].getVectorBlendVertex()[vertexId]
			Local currentWeight:Float = submesh.getMorphTargetWeight(morphTargetId)
			position.x += currentWeight * blendVertex.position.x
			position.y += currentWeight * blendVertex.position.y
			position.z += currentWeight * blendVertex.position.z
		Next
	Endif

	' initialize vertex
	Local x:Float, y:Float, z:Float
	x = 0
	y = 0
	z = 0

	' blend together all vertex influences
	Local v:CalVector = New CalVector
	Local influenceCount:Int = vertex.vectorInfluence.length
	If influenceCount = 0 then
		x = position.x
		y = position.y
		z = position.z
	Else
		For Local influenceId = 0 To influenceCount-1
			' get the influence
			Local influence:CalInfluence = vertex.vectorInfluence[influenceId]

			' get the bone of the influence vertex
			Local bone:CalBone = vectorBone[influence.boneId]

			' transform vertex with current state of the bone
			v.assign(position)
			v.multMatrixLocal(bone.getTransformMatrix())
			v.addLocal(bone.getTranslationBoneSpace())
			
			x += influence.weight * v.x
			y += influence.weight * v.y
			z += influence.weight * v.z
		Next
	Endif

	Return New CalVector(x * m_axisFactorX, y * m_axisFactorY, z * m_axisFactorZ)		
	
	End
	
	Method calculateVerticesAndNormals:Int(submesh:CalSubmesh, vertexBuffer:Float[], stride:Int=6)
	
		If stride <= 0 Then
			stride = 6
		Endif
		
		If vertexBuffer.Length < submesh.getVertexCount() * stride Then
			Return 0
		Endif
		
		' get bone vector of the skeleton
		Local vectorBone:CalBone[] = m_model.getSkeleton().getVectorBone()
	
		' get vertex vector of the submesh
		Local vectorVertex:CalVertex[] = submesh.getCoreSubmesh().getVectorVertex()
	
		' get physical property vector of the core submesh
		Local vectorPhysicalProperty:CalPhysicalProperty[] = submesh.getCoreSubmesh().getVectorPhysicalProperty()
	
		' get the number of vertices
		Local vertexCount:Int = submesh.getVertexCount()
	
		' get the sub morph target vector from the core sub mesh
		Local vectorSubMorphTarget:CalCoreSubMorphTarget[] = submesh.getCoreSubmesh().getVectorCoreSubMorphTarget()
	
		' calculate the base weight
		Local baseWeight:Float = submesh.getBaseWeight()
	
		' get the number of morph targets
		Local morphTargetCount:Int = submesh.getMorphTargetWeightCount()
	
		' calculate all submesh vertices
		Local vi:int = 0
		Local v:CalVector = New CalVector
		Local n:CalVector = New CalVector
		Local position:CalVector = New CalVector
		Local normal:CalVector = New CalVector
		For Local vertexId:Int = 0 To vertexCount-1
			' get the vertex
			Local vertex:CalVertex = vectorVertex[vertexId]
	
			' blend the morph targets
			position.assign(0, 0, 0)
			normal.assign(0, 0, 0)
			If baseWeight = 1 then
				position.x = vertex.position.x
				position.y = vertex.position.y
				position.z = vertex.position.z
				normal.x = vertex.normal.x
				normal.y = vertex.normal.y
				normal.z = vertex.normal.z
			Else
				position.x = baseWeight * vertex.position.x
				position.y = baseWeight * vertex.position.y
				position.z = baseWeight * vertex.position.z
				normal.x = baseWeight * vertex.normal.x
				normal.y = baseWeight * vertex.normal.y
				normal.z = baseWeight * vertex.normal.z
	
				For Local morphTargetId:Int = 0 To morphTargetCount-1
					Local blendVertex:CalBlendVertex = vectorSubMorphTarget[morphTargetId].getVectorBlendVertex()[vertexId]
					Local currentWeight:Float = submesh.getMorphTargetWeight(morphTargetId)
					position.x += currentWeight * blendVertex.position.x
					position.y += currentWeight * blendVertex.position.y
					position.z += currentWeight * blendVertex.position.z
					normal.x += currentWeight * blendVertex.normal.x
					normal.y += currentWeight * blendVertex.normal.y
					normal.z += currentWeight * blendVertex.normal.z
				Next
			Endif
	
			' initialize vertex
			Local x:Float, y:Float, z:Float
			x = 0
			y = 0
			z = 0
	
			' initialize normal
			Local nx:Float, ny:Float, nz:Float
			nx = 0
			ny = 0
			nz = 0
	
			' blend together all vertex influences
			Local influenceCount:Int = vertex.vectorInfluence.Length
			If influenceCount = 0 then
				x = position.x
				y = position.y
				z = position.z
				nx = normal.x
				ny = normal.y
				nz = normal.z
			Else
				For Local influenceId:Int = 0 To influenceCount-1
					' get the influence
					Local influence:CalInfluence = vertex.vectorInfluence[influenceId]
	
					' get the bone of the influence vertex
					Local bone:CalBone = vectorBone[influence.boneId]
	
					' transform vertex with current state of the bone
					v.assign(position)
					v.multMatrixLocal(bone.getTransformMatrix())
					v.addLocal(bone.getTranslationBoneSpace())
					
					x += influence.weight * v.x
					y += influence.weight * v.y
					z += influence.weight * v.z
	
					' transform normal with current state of the bone
					n.assign(normal)
					n.multMatrixLocal(bone.getTransformMatrix())
	
					nx += influence.weight * n.x
					ny += influence.weight * n.y
					nz += influence.weight * n.z
				Next
			Endif
	
			' save vertex position
			If submesh.getCoreSubmesh().getSpringCount() > 0 And submesh.hasInternalData() = True Then
				' get the pgysical property of the vertex
				Local physicalProperty:CalPhysicalProperty = vectorPhysicalProperty[vertexId]
	
				' assign new vertex position if there is no vertex weight
				If physicalProperty.weight = 0 then
					vertexBuffer[vi    ] = x * m_axisFactorX
					vertexBuffer[vi + 1] = y * m_axisFactorY
					vertexBuffer[vi + 2] = z * m_axisFactorZ
				Endif
			Else
				vertexBuffer[vi    ] = x * m_axisFactorX
				vertexBuffer[vi + 1] = y * m_axisFactorY
				vertexBuffer[vi + 2] = z * m_axisFactorZ
			Endif
	
			' re-normalize normal if necessary
			If m_normalize = True Then
				nx /= m_axisFactorX
				ny /= m_axisFactorY
				nz /= m_axisFactorZ
	
				Local scale:Float = 1 / Sqrt(nx * nx + ny * ny + nz * nz)
	
				vertexBuffer[vi + 3] = nx * scale
				vertexBuffer[vi + 4] = ny * scale
				vertexBuffer[vi + 5] = nz * scale
			Else
				vertexBuffer[vi + 3] = nx
				vertexBuffer[vi + 4] = ny
				vertexBuffer[vi + 5] = nz
			Endif
	
			vi += stride
		Next
	
		Return vertexCount		
	
	End
	
	'Use this one with minib3d
	
	Method calculateVerticesNormalsAndTexCoords:Int(submesh:CalSubmesh, vertexBuffer:Float[], numTexCoords:Int)
	
		If numTexCoords < 0 Then
			numTexCoords = 0
		Endif
		' get bone vector of the skeleton
		Local vectorBone:CalBone[] = m_model.getSkeleton().getVectorBone()
	
		' get vertex vector of the submesh
		Local vectorVertex:CalVertex[] = submesh.getCoreSubmesh().getVectorVertex()
	
		' get the texture coordinate vector vector
		Local vectorvectorTextureCoordinate:CalTextureCoordinate[][] = submesh.getCoreSubmesh().getVectorVectorTextureCoordinate()
	
		Local textureCoordinateCount:Int = vectorvectorTextureCoordinate.Length
		'Print "NOF Texcoords: "+textureCoordinateCount
		' check if the given texture coord count is valid
		If numTexCoords < 0 Or numTexCoords > textureCoordinateCount Then
			If textureCoordinateCount <> 0 Then
				Return -1
			Endif
		Endif
	
		' get physical property vector of the core submesh
		Local vectorPhysicalProperty:CalPhysicalProperty[] = submesh.getCoreSubmesh().getVectorPhysicalProperty()
	
		' get the number of vertices
		Local vertexCount:Int = submesh.getVertexCount()
	
		' get the sub morph target vector from the core sub mesh
		Local vectorSubMorphTarget:CalCoreSubMorphTarget[] = submesh.getCoreSubmesh().getVectorCoreSubMorphTarget()
	
		' calculate the base weight
		Local baseWeight:Float = submesh.getBaseWeight()
	
		' get the number of morph targets
		Local morphTargetCount:Int = submesh.getMorphTargetWeightCount()
	
		' calculate all submesh vertices
		Local vi:Int = 0
		Local position:CalVector = New CalVector
		Local normal:CalVector = New CalVector
		For Local vertexId:Int = 0 To vertexCount-1
			' get the vertex
			Local vertex:CalVertex = vectorVertex[vertexId]
	
			' blend the morph targets
			position.assign(0, 0, 0)
			normal.assign(0, 0, 0)
			If baseWeight = 1 then
				position.x = vertex.position.x
				position.y = vertex.position.y
				position.z = vertex.position.z
				normal.x = vertex.normal.x
				normal.y = vertex.normal.y
				normal.z = vertex.normal.z
			Else
				position.x = baseWeight * vertex.position.x
				position.y = baseWeight * vertex.position.y
				position.z = baseWeight * vertex.position.z
				normal.x = baseWeight * vertex.normal.x
				normal.y = baseWeight * vertex.normal.y
				normal.z = baseWeight * vertex.normal.z
	
				For Local morphTargetId:Int = 0 To morphTargetCount-1
					Local blendVertex:CalBlendVertex = vectorSubMorphTarget[morphTargetId].getVectorBlendVertex()[vertexId]
					Local currentWeight:Float = submesh.getMorphTargetWeight(morphTargetId)
					position.x += currentWeight * blendVertex.position.x
					position.y += currentWeight * blendVertex.position.y
					position.z += currentWeight * blendVertex.position.z
					normal.x += currentWeight * blendVertex.normal.x
					normal.y += currentWeight * blendVertex.normal.y
					normal.z += currentWeight * blendVertex.normal.z
				Next
			Endif
	
			' initialize vertex
			Local x:Float, y:Float, z:Float
			x = 0
			y = 0
			z = 0
	
			' initialize normal
			Local nx:Float, ny:Float, nz:Float
			nx = 0
			ny = 0
			nz = 0
	
			' blend together all vertex influences
			Local influenceCount:Int = vertex.vectorInfluence.Length
			If influenceCount = 0 Then
				x = position.x
				y = position.y
				z = position.z
				nx = normal.x
				ny = normal.y
				nz = normal.z
			Else
				For Local influenceId:Int = 0 To influenceCount-1
					' get the influence
					Local influence:CalInfluence = vertex.vectorInfluence[influenceId]
	
					' get the bone of the influence vertex
					Local bone:CalBone = vectorBone[influence.boneId]
	
					' transform vertex with current state of the bone
					Local v:CalVector = New CalVector(position)
					v.multMatrixLocal(bone.getTransformMatrix())
					v.addLocal(bone.getTranslationBoneSpace())
	
					x += influence.weight * v.x
					y += influence.weight * v.y
					z += influence.weight * v.z
	
					' transform normal with current state of the bone
					Local n:CalVector = New CalVector(normal)
					n.multMatrixLocal(bone.getTransformMatrix())
	
					nx += influence.weight * n.x
					ny += influence.weight * n.y
					nz += influence.weight * n.z
				Next
			Endif
	
			' save vertex position
			If submesh.getCoreSubmesh().getSpringCount() > 0 And submesh.hasInternalData() = True Then
				' get the pgysical property of the vertex
				Local physicalProperty:CalPhysicalProperty = vectorPhysicalProperty[vertexId]
	
				' assign new vertex position if there is no vertex weight
				If physicalProperty.weight = 0 Then
					vertexBuffer[vi    ] = x * m_axisFactorX
					vertexBuffer[vi + 1] = y * m_axisFactorY
					vertexBuffer[vi + 2] = z * m_axisFactorZ
				Endif
			Else
				vertexBuffer[vi    ] = x * m_axisFactorX
				vertexBuffer[vi + 1] = y * m_axisFactorY
				vertexBuffer[vi + 2] = z * m_axisFactorZ
			Endif
	
			' re-normalize normal if necessary
			If m_normalize = True Then
				nx /= m_axisFactorX
				ny /= m_axisFactorY
				nz /= m_axisFactorZ
	
				Local scale:Float = 1 / Sqrt(nx * nx + ny * ny + nz * nz)
	
				vertexBuffer[vi + 3] = nx * scale
				vertexBuffer[vi + 4] = ny * scale
				vertexBuffer[vi + 5] = nz * scale
			Else
				vertexBuffer[vi + 3] = nx
				vertexBuffer[vi + 4] = ny
				vertexBuffer[vi + 5] = nz
			Endif
	
			vi = vi + 6
	
			If textureCoordinateCount = 0 Then
				vi = vi + numTexCoords * 2
			Else
				For Local mapId:Int = 0 To numTexCoords-1
					Local textureCoord:CalTextureCoordinate = vectorvectorTextureCoordinate[mapId][vertexId]
					vertexBuffer[vi    ] = textureCoord.u
					vertexBuffer[vi + 1] = textureCoord.v
	
					vi = vi + 2
				Next
			Endif
		Next
	
		Return vertexCount	
	
	End
	
	Method update:Void()
	
		' get the attached meshes vector
		Local vectorMesh:CalMesh[] = m_model.getVectorMesh()
	
		' loop through all the attached meshes
		For Local meshId:Int = 0 To vectorMesh.Length-1
			' get the submesh vector of the mesh
			Local vectorSubmesh:CalSubmesh[] = vectorMesh[meshId].getVectorSubmesh()
	
			' loop through all the submeshes of the mesh
			For Local submeshId:Int = 0 To vectorSubmesh.Length-1
				Local submesh:CalSubmesh = vectorSubmesh[submeshId]
				' check if the submesh handles vertex data internally
				If submesh.hasInternalData() = True then
					' calculate the transformed vertices and normals and store them in the submesh
					Local vectorVertex:CalVector[] = submesh.getVectorVertex()
					Local vectorNormal:CalVector[] = submesh.getVectorNormal()
					calculateVerticesAndNormalsInternal(submesh, vectorVertex, vectorNormal)
	
					Local vectorTangentSpaceCount:Int = submesh.getVectorVectorTangentSpace().Length
					For Local mapId:Int = 0 To vectorTangentSpaceCount-1
						If submesh.isTangentsEnabled(mapId) = True Then
							Local vectorTangentSpace:CalTangentSpace[] = submesh.getVectorVectorTangentSpace()[mapId]
							calculateTangentSpacesInternal(submesh, mapId, vectorTangentSpace)
							'submesh:CalSubmesh, mapId:Int, tangentSpaces:CalTangentSpace[]
						Endif
					Next
				Endif
			Next
		Next	
	
	End
	
	
	Method setNormalization:Void(normalize:Bool)
		m_normalize = normalize
	End
	
	Method setAxisFactorX:Void(factor:Float)
		m_axisFactorX = factor
		m_normalize = True
	End

	Method setAxisFactorY:Void(factor:Float)
		m_axisFactorY = factor
		m_normalize = True
	End
	
	Method setAxisFactorZ:Void(factor:Float)
		m_axisFactorZ = factor
		m_normalize = True
	End	
	
	Method calculateVerticesAndNormalsInternal:Int(submesh:CalSubmesh, veritces:CalVector[], normals:CalVector[])
		If veritces.Length < submesh.getVertexCount() Or normals.Length < submesh.getVertexCount() Then
			Print "internal error: buffer is not large enough to contain all the vertex/normal data"
			Return 0
		Endif
		' get bone vector of the skeleton
		Local vectorBone:CalBone[] = m_model.getSkeleton().getVectorBone()
	
		' get vertex vector of the submesh
		Local vectorVertex:CalVertex[] = submesh.getCoreSubmesh().getVectorVertex()
	
		' get physical property vector of the core submesh
		Local vectorPhysicalProperty:CalPhysicalProperty[] = submesh.getCoreSubmesh().getVectorPhysicalProperty()
	
		' get the number of vertices
		Local vertexCount:Int = submesh.getVertexCount()
	
		' get the sub morph target vector from the core sub mesh
		Local vectorSubMorphTarget:CalCoreSubMorphTarget[] = submesh.getCoreSubmesh().getVectorCoreSubMorphTarget()
	
		' calculate the base weight
		Local baseWeight:Float = submesh.getBaseWeight()
	
		' get the number of morph targets
		Local morphTargetCount:Int = submesh.getMorphTargetWeightCount()
	
		' calculate all submesh vertices
		Local v:CalVector = New CalVector
		Local n:CalVector = New CalVector
		Local position:CalVector = New CalVector
		Local normal:CalVector = New CalVector
		For Local vertexId:Int = 0 To vertexCount-1
			' get the vertex
			Local vertex:CalVertex = vectorVertex[vertexId]
	
			' blend the morph targets
			position.assign(0, 0, 0)
			normal.assign(0, 0, 0)
			If baseWeight = 1 then
				position.x = vertex.position.x
				position.y = vertex.position.y
				position.z = vertex.position.z
				normal.x = vertex.normal.x
				normal.y = vertex.normal.y
				normal.z = vertex.normal.z
			Else
				position.x = baseWeight * vertex.position.x
				position.y = baseWeight * vertex.position.y
				position.z = baseWeight * vertex.position.z
				normal.x = baseWeight * vertex.normal.x
				normal.y = baseWeight * vertex.normal.y
				normal.z = baseWeight * vertex.normal.z
	
				For Local morphTargetId:Int = 0 To morphTargetCount-1
					Local blendVertex:CalBlendVertex = vectorSubMorphTarget[morphTargetId].getVectorBlendVertex()[vertexId]
					Local currentWeight:Float = submesh.getMorphTargetWeight(morphTargetId)
					position.x += currentWeight * blendVertex.position.x
					position.y += currentWeight * blendVertex.position.y
					position.z += currentWeight * blendVertex.position.z
					normal.x += currentWeight * blendVertex.normal.x
					normal.y += currentWeight * blendVertex.normal.y
					normal.z += currentWeight * blendVertex.normal.z
				Next
			Endif
	
			' initialize vertex
			Local x:Float, y:Float, z:Float
			x = 0
			y = 0
			z = 0
	
			' initialize normal
			Local nx:Float, ny:Float, nz:Float
			nx = 0
			ny = 0
			nz = 0
	
			' blend together all vertex influences
			Local influenceCount:Int = vertex.vectorInfluence.Length
			If influenceCount = 0 Then
				x = position.x
				y = position.y
				z = position.z
				nx = normal.x
				ny = normal.y
				nz = normal.z
			Else
				For Local influenceId:Int = 0 To influenceCount-1
					' get the influence
					Local influence:CalInfluence = vertex.vectorInfluence[influenceId]
	
					' get the bone of the influence vertex
					Local bone:CalBone = vectorBone[influence.boneId]
	
					' transform vertex with current state of the bone
					v.assign(position)
					v.multMatrixLocal(bone.getTransformMatrix())
					v.addLocal(bone.getTranslationBoneSpace())
					
					x += influence.weight * v.x
					y += influence.weight * v.y
					z += influence.weight * v.z
	
					' transform normal with current state of the bone
					n.assign(normal)
					n.multMatrixLocal(bone.getTransformMatrix())
	
					nx += influence.weight * n.x
					ny += influence.weight * n.y
					nz += influence.weight * n.z
				Next
			Endif
	
			If veritces[vertexId] = Null then
				veritces[vertexId] = New CalVector
			Endif
			If normals[vertexId] = Null Then
				normals[vertexId] = New CalVector
			Endif
			
			' save vertex position
			If submesh.getCoreSubmesh().getSpringCount() > 0 And submesh.hasInternalData() Then
				' get the pgysical property of the vertex
				Local physicalProperty:CalPhysicalProperty = vectorPhysicalProperty[vertexId]
	
				' assign new vertex position if there is no vertex weight
				If physicalProperty.weight = 0 then
					veritces[vertexId].assign(x * m_axisFactorX, y * m_axisFactorY, z * m_axisFactorZ)
				Endif
			Else
				veritces[vertexId].assign(x * m_axisFactorX, y * m_axisFactorY, z * m_axisFactorZ)
			endif
	
			' re-normalize normal if necessary
			If  m_normalize = True Then
				nx /= m_axisFactorX
				ny /= m_axisFactorY
				nz /= m_axisFactorZ
	
				Local scale:Float = 1 / Sqrt(nx * nx + ny * ny + nz * nz)
	
				normals[vertexId].assign(nx * scale, ny * scale, nz * scale)
			Else
				normals[vertexId].assign(nx, ny, nz)
			Endif
		Next
	
		Return vertexCount	
	End
	
	Method calculateTangentSpacesInternal:Int(submesh:CalSubmesh, mapId:Int, tangentSpaces:CalTangentSpace[])

		If mapId < 0 Or mapId >= submesh.getCoreSubmesh().getVectorVectorTangentSpace().Length Then
			Print "internal error: mapId is out of range"
			Return 0
		Endif
		
		If tangentSpaces.Length < submesh.getVertexCount() Then
			Print "internal error: buffer is not large enough to contain all the tangent space data"
			Return 0
		Endif
		
		' get bone vector of the skeleton
		Local vectorBone:CalBone[] = m_model.getSkeleton().getVectorBone()
	
		' get vertex vector of the submesh
		Local vectorVertex:CalVertex[] = submesh.getCoreSubmesh().getVectorVertex()
	
		' get tangent space vector of the submesh
		Local vectorTangentSpace:CalTangentSpace[] = submesh.getCoreSubmesh().getVectorVectorTangentSpace()[mapId]
	
		' get the number of vertices
		Local vertexCount:Int = submesh.getVertexCount()
	
		' calculate tangent for all submesh vertices
		Local v:CalVector = New CalVector
		For Local vertexId:Int = 0 To vertexCount-1
			Local tangentSpace:CalTangentSpace = vectorTangentSpace[vertexId]
	
			' get the vertex
			Local vertex:CalVertex = vectorVertex[vertexId]
	
			' initialize tangent
			Local tx:Float, ty:Float, tz:Float
			tx = 0
			ty = 0
			tz = 0
	
			' blend together all vertex influences
			Local influenceCount:Int = vertex.vectorInfluence.Length
			For Local influenceId:Int = 0 To influenceCount-1
				' get the influence
				Local influence:CalInfluence = vertex.vectorInfluence[influenceId]
	
				' get the bone of the influence vertex
				Local bone:CalBone = vectorBone[influence.boneId]
	
				' transform normal with current state of the bone
				v.assign(tangentSpace.tangent)
				v.multMatrixLocal(bone.getTransformMatrix())
	
				tx += influence.weight * v.x
				ty += influence.weight * v.y
				tz += influence.weight * v.z
			Next
	
			If tangentSpaces[vertexId] = Null then
				tangentSpaces[vertexId] = new CalTangentSpace
			Endif
			' re-normalize tangent if necessary
			If m_normalize = True then
				tx /= m_axisFactorX
				ty /= m_axisFactorY
				tz /= m_axisFactorZ
	
				Local scale:Float = 1 / Sqrt(tx * tx + ty * ty + tz * tz)
	
				tangentSpaces[vertexId].tangent.assign(tx * scale, ty * scale, tz * scale)
			Else 
				tangentSpaces[vertexId].tangent.assign(tx, ty, tz)
			Endif
	
			tangentSpaces[vertexId].crossFactor = tangentSpace.crossFactor
		Next
	
		Return vertexCount	
	
	End


End Class